<template>
    <div></div>
</template>

<script>
//引入Jquery
import "../../assets/resize/jquery-1.4.2";
import "../../assets/resize/jquery.resizable";
export default {
    name: "baseComp",
    props: {
        //事件属性配置
        eventConfig: {
            type: Object,
            default: () => {
                return {}
            }
        },
        //当前组件json点分制路径path
        path: '',
        //当前组件的页面树path路径
        pagePath: '',
        //当前组件配置的属性样式
        styleAttr: Object,
        //当前组件推拽的属性配置
        dragAttr: Object,
        //属性值
        inData: [Object,Array,String,Number],
        //数据刷新配置项
        dataRefresh: Object,
        //主题内容
        theme: {
            type: String,
            default(){
                return 'default'
            }
        },
    },
    watch: {
        //事件属性配置
        eventConfig: {
            handler(val){
                this.currentEventConfig = this.deepClone(val);
            },
            deep: true,
            immediate: true
        },
        //数据刷新配置
        dataRefresh: {
            handler(val){
                if (val){
                    //创建定时器，定时刷新表格数据
                    if(val.isUseTimer){
                        if (this.timer){
                            // 先清除定时器
                            this.closeTimer();
                        }
                        // 重新使用新的时间间隔开启一个新的定时器
                        this.initTimer(val.intervalTime);
                    }else {
                        this.closeTimer();
                    }
                    //创建主题订阅
                    if (val.isUseWs){
                        this.subscriptModel();
                    }else {
                        this.unSubscribe();
                    }
                }
            },
            immediate:true,
            deep:true
        }
    },
    destroyed(){
        if(this.dataRefresh && this.dataRefresh.isUseTimer){
            this.closeTimer();
        }
        if(this.dataRefresh && this.dataRefresh.isUseWs){
            this.unSubscribe();
        }
    },
    data(){
        return{
            currentEventConfig: {}, //当前事件的属性配置信息
            timer: null,  //定时器
            commpStyle: this.styleAttr,
            currentTheme: this.theme //当前主题内容
        }
    },
    mounted(){

    },
    created(){
        this.initDrag();
        this.registerCommp();
    },
    methods: {
        /**
         * 组件初始化函数，用于组件初始化序列化时调用，
         * 每个组件根据组件业务逻辑实现初始化函数
         */
        init(){},
        /**
         * 组件更新函数，用于组件在更新数据时使用，通过界面手动或则websocket主动推送方式进行更新操作。
         * 数据需要以json的格式传入，且应包含数据唯一键。
         * 组件需要根据组件业务逻辑自行实现更新逻辑。
         * @param {需要更新的数据内容} data
         */
        update(data){},
        /**
         * 组件删除函数，用于组件在删除数据时使用
         * 数据需要以json的格式传入，且应包含数据唯一键。
         * 组件需要根据组件业务逻辑自行实现删除逻辑。
         * @param {需要组件删除的数据内容} data
         */
        delete(data){},
        /**
         * 组件新增插入函数，用于对组件进行插入新数据实现。
         * @param {需要组件新增的数据内容} data
         */
        insert(data){},
        /**
         * 初始化拖拽配置
         */
        initDrag(){
            this.$nextTick(() => {
                //判断当前布局组件是否开启拖拽功能
                if (this.dragAttr && this.dragAttr.resizable){
                    let handles;
                    if(this.dragAttr.direction){
                        handles = this.dragAttr.direction.join(",");
                    }else{
                        handles = 'e,s';
                    }
                    //获取当前组件顶层元素，并给顶层元素添加拖拽能力
                    let currentEl = this.$el;
                    jQuery(currentEl).resizable({
                        handles : handles,
                        helper : true,
                        helperStyle : {
                            "border" : "1px solid #888"
                        },
                        maxHeight : jQuery(window).height() - 60,
                        maxWidth : jQuery(window).width() - 60,
                        minHeight : 60,
                        minWidth : 60,
                        onStartResize : function() {
                        },
                        onResize : function() {
                        },
                        onStopResize : function(el, e) {
                            let width = el.width();
                            let height = el.height();
                            let next = el.next();
                            let direction = e.data.dir;
                            let startWidth = e.data.startWidth - e.data.deltaWidth;
                            let startHeight = e.data.startHeight - e.data.deltaHeight;
                            //左右
                            if (direction == 'e'){
                                let offsetWidth = startWidth-width;
                                console.log("宽度偏移量", offsetWidth)
                                //获取布局组件列元素
                                let layoutCol = el.parent();
                                let layoutNextCol;
                                let className = layoutCol.attr("class");
                                //判断是否为布局组件列元素，如果是则直接取用列的下一个兄弟节点
                                if(className == 'resizableCol'){
                                    layoutNextCol = layoutCol.next();
                                }else{
                                    layoutNextCol = el.next();
                                }
                                layoutNextCol.width(layoutNextCol.width() + offsetWidth);
                            }
                            //上下
                            else if (direction == "s"){
                                let offsetHeight = startHeight-height;
                                //获取布局组件行元素
                                let layoutRow = el.parent().parent();
                                let className = layoutRow.attr("class");
                                let layoutNextRow;
                                //判断是否为布局组件行元素，如果是则直接取用行的下一个兄弟节点
                                if(className == 'resizableRow'){
                                    layoutNextRow = layoutRow.next();
                                }else{
                                    layoutNextRow = el.next();
                                }
                                console.log("高度偏移量", offsetHeight)
                                layoutNextRow.height(layoutNextRow.height() + offsetHeight)
                            }
                        }
                    })
                }
            })
        },
        /**
         * 注册组件树
         */
        registerCommp(){
            try{
                let commp = eval(this.pagePath);
                if(commp){
                    commp.instance = this;
                }
            }catch(err){
                console.log("当前页面没有注册到组件树中", this.pagePath);
            }
        },

        /**
         * 加载主题，需要在每个组件实例中，组件实例化完成后主动调用该函数进行主题加载。
         */
        loadTheme(themeFileName){
            import("../../assets/theme/"+this.theme+"/"+themeFileName+"/"+themeFileName+".css").then(res => {
                console.log(themeFileName,"==>"+this.theme+"==>主题加载完成");
            })
        },
        /**
         * 动态执行指定事件，动态执行组件事件event配置表中的事件。
         * @param eventName 事件名
         * @param params 事件参数对象
         */
        executeEvent(eventName, path, ...params){
            //动态封装拼接需要执行的函数体，以及函数参数内容
            this.$emit(eventName, path, eventName, params);
        },

        /**
         * 初始化定时器，具体实现需要到各自组件中根据需要实现定时调度
         * @param intervalTime
         */
        initTimer(intervalTime) {

        },
        /**
         * 关闭timer定时器
         */
        closeTimer(){
            if (this.timer){
                // 先清除定时器
                clearInterval(this.timer);
                this.timer = null;
            }
        },
        /**
         * 初始化ws订阅功能，具体实现需要到各自组件中根据需要实现主题订阅
         */
        subscriptModel() {
            let model = {};
            for (let eventKey in this.dataRefresh.subscriptModel.event) {
                model[eventKey] = (res) => {
                    //组装数据订阅刷新接口函数path路劲
                    let refreshEventPath = this.path+".dataRefresh.subscriptModel.params"
                    this.dataRefresh.subscriptModel.event[eventKey](refreshEventPath, eventKey, res);
                }
            }
            if (this.isEmptyObject(model)){
                return;
            }
            let ws;
            if (!this.$websocket){
                ws = this[this.dataRefresh.connectName];
            }else {
                ws = this.$websocket;
            }
            if (ws && this.dataRefresh.topicName){
                ws.subscribeToModel(this.dataRefresh.topicName, model, {});
            }
        },
        /**
         * 取消主题订阅
         */
        unSubscribe() {
            let ws;
            if (!this.$websocket){
                ws = this[this.dataRefresh.connectName];
            }else {
                ws = this.$websocket;
            }
            if (ws && this.dataRefresh.topicName){
                ws.unSubscribe(this.dataRefresh.topicName);
            }
        },
        /**
         * 统一获取组件渲染内容
         * @param item
         * @returns {string|*|string}
         */
        getComponent(item){
            if (!item || !item.component){
                return 'commonText';
            }
            if(item.component.startsWith('custom')){
                return item.component.replaceAll('custom_', "");
            }
            if (item.component == 'number'){
                return 'avue-input-number';
            }
            return 'avue-'+item.component;
        },
        /**
         * 获取组件绑定传入参数
         * @param item
         */
        getComponentParams(item){
            if (!item){
                return {};
            }
            let compConfig = item.config;
            if (compConfig){
                // 为主键时
                let size = "small";
                if(compConfig.hasOwnProperty('component')){
                  size = compConfig.params && compConfig.params.size || 'small'
                }else{
                  size = compConfig && compConfig.size || 'small'
                }
                const vBind = Object.assign(this.deepClone(compConfig), compConfig.params, {
                    size: size,
                    dic: compConfig.dicData ? compConfig.dicData.map(d => {
                        if (!compConfig.props) return d
                        const { label, value, desc } = compConfig.props
                        if (!label || !value) return d
                        return {
                            [label]: d.label,
                            [value]: d.value,
                            [desc]: d.desc
                        }
                    }) : undefined,
                    rules: compConfig.pattern ? compConfig.rules.map(r => {
                        if (r.pattern) r.pattern = new RegExp(compConfig.pattern)
                        return r
                    }) : compConfig.rules
                })
                vBind.inData = this.inData;
                if(['time', 'timerange', 'checkbox'].includes(vBind.type)){
                    vBind.value = vBind.dicData;
                }
                let event = ['change', 'blur', 'click', 'focus']
                event.forEach(e => delete vBind[e])
                if (vBind.event) delete vBind.event
                return vBind
            }
            return {};
        },
        /**
         * 获取组件绑定函数
         * @param item
         */
        getComponentEvent(item){
            if (!item){
                return {};
            }
            let compConfig = item.config;
            if (compConfig){
                let events = {};
                if (compConfig.event){
                    events = {...compConfig.event};
                }
                let inEvent = ['change', 'blur', 'click', 'focus']
                inEvent.forEach(e => {
                    let eEvent = compConfig[e];
                    if (eEvent){
                        events[e] = eEvent;
                    }
                })
                return events;
            }
            return {}
        },
        /**
         * 获取组件html
         */
        getComponentHtml(item){
            if (!item){
                return "";
            }
            let compConfig = item.config;
            if (compConfig){
                if (compConfig.params){
                    return compConfig.params.html;
                }
            }
            return "";
        },
        /**
         * 获取当前点击组件的json配置数据
         */
        queryCompJsonByPath(index, keys, json){
            let element = json[keys[index]];
            if (index == keys.length - 1) {
                return element;
            }
            return this.queryCompJsonByPath(index+1, keys, element);
        },
        /**
         * 判断对象是否为空对象
         * obj.constructor === Object 条件确认了对象确实是一个普通的对象。有时候，一个看似为空的对象实际上可能是一个 null、undefined、数字、字符串、boolean 或 Symbol
         * @param obj
         * @returns {boolean}
         */
        isEmptyObject(obj) {
            return Object.keys(obj).length === 0 && obj.constructor === Object;
        }
    }
}
</script>

<style scoped>

</style>
